package org.zachary.creditbusiness.commodityandhouse.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.zachary.commonmodule.entity.MqTransmissionJson;
import org.zachary.creditbusiness.commodityandhouse.entity.HouseOrder;
import org.zachary.creditbusiness.commodityandhouse.mapper.HouseOrderMapper;
import org.zachary.creditbusiness.commodityandhouse.util.KafkaProducerService;
import org.zachary.creditbusiness.hotel.util.UUIdUtil;
import org.zachary.creditbusiness.hotel.entity.Ban;
import org.zachary.creditbusiness.hotel.mapper.BanMapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

@Component
public class SendHouseOrder {

    private static final int DEFAULT_SERVICE_TYPE = 6; // 租房服务类型 (LeaseOfHouses)
    private static final DateTimeFormatter FORMATTER =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private HouseOrderMapper houseOrderMapper;

    @Autowired
    private KafkaProducerService kafkaProducerService;

    @Autowired
    private BanMapper banMapper;

    /**
     * 根据订单ID查询数据库，并将对应信息组装成 MqTransmissionJson 发到 Kafka。
     * 只有在以下情况下才发送消息：
     * 1. 守约支付后
     * 2. 逾期当天发送消息
     * 3. 逾期后支付发送消息
     *
     * @param orderId 订单主键
     */
    public void sendMessage(Integer orderId) {
        // 1. 查询订单
        HouseOrder order = houseOrderMapper.selectById(orderId);
        if (order == null) {
            throw new IllegalArgumentException("未找到订单，orderId=" + orderId);
        }

        // 2. 判断是否需要发送消息
        if (!shouldSendMessage(order)) {
            System.out.println("订单ID: " + orderId + " 不满足发送消息条件，跳过");
            return;
        }

        // 3. 逾期 & 支付状态、金额、逾期期数
        // 修正逾期判断逻辑：
        // promise=2表示逾期后支付，应该标记为逾期
        // promise=1且未支付表示当前逾期
        // 或者根据实际支付时间与截止时间比较判断是否逾期
        boolean isOverdue = (order.getPromise() != null && order.getPromise() == 2) ||
                (order.getPromise() != null && order.getPromise() == 1 &&
                        (order.getStatus() == null || order.getStatus() == 0)) ||
                (order.getPayDate() != null && order.getDeadline() != null &&
                        order.getPayDate().after(order.getDeadline()));
        boolean isPaid = true;
        double amount;
        int overduePeriod;

        // 判断是逾期当天发送初始记录还是逾期支付后发送更新记录
        if (order.getPromise() != null && order.getPromise() == 1 &&
                (order.getStatus() == null || order.getStatus() == 0)) {
            // 逾期当天发送初始逾期记录：overduePeriod=-1, amount=0.0, finishTime=null
            overduePeriod = -1;
            amount = 0.0;
        } else {
            // 逾期支付后发送更新记录：正常的逾期期数和金额
            overduePeriod = calculateOverduePeriod(order);
            amount = order.getPrice() != null ? order.getPrice().doubleValue() : 0.0;

            // 调试日志：输出逾期期数计算结果
            System.out.println("逾期期数计算详情 - 订单ID: " + order.getId() +
                    ", 截止时间: " + order.getDeadline() +
                    ", 支付时间: " + order.getPayDate() +
                    ", 计算出的逾期期数: " + overduePeriod);
        }

        // 4. 获取或生成UUID
        String uuid = order.getUuid();
        if (uuid == null || uuid.trim().isEmpty()) {
            // 如果订单没有UUID，生成一个新的并保存到数据库
            uuid = UUIdUtil.createUUId();
            // 使用安全的更新方式，只更新uuid字段，避免意外修改deadline等其他字段
            UpdateWrapper<HouseOrder> uuidUpdateWrapper = new UpdateWrapper<>();
            uuidUpdateWrapper.eq("id", order.getId()).set("uuid", uuid);
            houseOrderMapper.update(null, uuidUpdateWrapper);
        }

        // 5. 转换 Timestamp -> Instant（按北京时区）
        Instant dueTime = parseToInstant(order.getDeadline());
        Instant finishTime;

        // 逾期当天发送初始记录时，finishTime必须为null
        if (order.getPromise() != null && order.getPromise() == 1 &&
                (order.getStatus() == null || order.getStatus() == 0)) {
            finishTime = null;
        } else {
            finishTime = order.getPayDate() != null ? parseToInstant(order.getPayDate()) : null;
        }

        // 6. 检查是否需要封禁（逾期超过180天）
        checkAndBanIfNeeded(order, uuid);

        // 7. 构建并发送
        MqTransmissionJson payload = new MqTransmissionJson(
                uuid,
                order.getUserId(),
                DEFAULT_SERVICE_TYPE,
                isOverdue,
                overduePeriod,
                isPaid,
                amount,
                isOverdue ? "房屋租赁-逾期还款订单" : "房屋租赁-守约订单",
                dueTime,
                finishTime
        );
        kafkaProducerService.sendJsonMessage("TestTopic", payload);

        // 如果是逾期当天发送的初始消息，标记为已发送避免重复
       /* if (order.getPromise() != null && order.getPromise() == 1 &&
                (order.getStatus() == null || order.getStatus() == 0)) {
            // 使用安全的更新方式，只更新overdueMessageSent字段，避免意外修改deadline等其他字段
            UpdateWrapper<HouseOrder> messageUpdateWrapper = new UpdateWrapper<>();
            messageUpdateWrapper.eq("id", order.getId()).set("overdue_message_sent", true);
           // houseOrderMapper.update(null, messageUpdateWrapper);
        }*/

        System.out.println("租房订单逾期当天信用分消息发送成功 - 订单ID: " + orderId +
                ", 完整消息: uuid=" + uuid +
                ", userId=" + order.getUserId() +
                ", serviceType=" + DEFAULT_SERVICE_TYPE +
                ", isOverdue=" + isOverdue +
                ", overduePeriod=" + overduePeriod +
                ", isPaid=" + isPaid +
                ", amount=" + amount +
                ", desc=" + (isOverdue ? "房屋租赁-逾期还款订单" : "房屋租赁-守约订单") +
                ", dueTime=" + dueTime +
                ", finishTime=" + finishTime);
    }

    /**
     * 判断是否需要发送消息到消息队列
     * 条件：
     * 1. 守约支付后（status = 1 且 payDate 不为空）
     * 2. 逾期当天发送消息（promise = 1 且未支付且未发送过逾期消息）
     * 3. 逾期后支付发送消息（status = 1 且 promise = 2）
     */
    private boolean shouldSendMessage(HouseOrder order) {
        // 条件1：用户支付订单时（包括守约支付和逾期后支付）
        if (order.getStatus() != null && order.getStatus() == 1 && order.getPayDate() != null) {
            return true;
        }

        // 条件2：逾期当天发送消息（promise = 1 表示逾期状态且未支付且未发送过逾期消息）
        // 修复：使用Byte类型比较，避免Integer与Byte类型不匹配的问题
        // 新增：检查是否已发送过逾期消息，避免重复发送
        if (order.getPromise() != null && order.getPromise() == 1 &&
                (order.getStatus() == null || order.getStatus() == 0) &&
                (order.getOverdueMessageSent() == null || !order.getOverdueMessageSent())) {
            return true;
        }

        return false;
    }

    /**
     * 计算逾期期数
     * 根据逾期天数确定期数：
     * 0天: 期数0（守约）
     * 1-30天: 期数1 (对应minusscore1)
     * 30-60天: 期数2 (对应minusscore2)
     * 60-90天: 期数3 (对应minusscore3)
     * 90-180天: 期数4 (对应minusscore4)
     * 180天以上: 期数5 (对应minusscoredeadline)
     */
    private int calculateOverduePeriod(HouseOrder order) {
        if (order.getDeadline() == null) {
            return 0;
        }

        // 确定比较时间：如果已支付使用支付时间，否则使用当前时间
        Timestamp compareTime;
        if (order.getStatus() != null && order.getStatus() == 1 && order.getPayDate() != null) {
            compareTime = order.getPayDate(); // 已支付，使用支付时间
        } else {
            compareTime = Timestamp.valueOf(LocalDateTime.now()); // 未支付，使用当前时间
        }

        long diffInMillis = compareTime.getTime() - order.getDeadline().getTime();

        // 修复：只要超过截止时间就算逾期，哪怕只有几分钟
        if (diffInMillis <= 0) {
            return 0; // 未逾期，守约
        }

        // 计算逾期天数（向上取整，确保任何逾期都至少算1天）
        long diffInDays = (diffInMillis + 24 * 60 * 60 * 1000 - 1) / (24 * 60 * 60 * 1000);

        if (diffInDays < 30) {
            return 1; // 1-29天，阶段1
        } else if (diffInDays < 60) {
            return 2; // 30-59天，阶段2
        } else if (diffInDays < 90) {
            return 3; // 60-89天，阶段3
        } else if (diffInDays < 180) {
            return 4; // 90-179天，阶段4
        } else {
            return 5; // 180天以上，阶段5
        }
    }

    /**
     * 检查是否需要封禁用户（逾期超过180天）
     * @param order 房屋订单
     * @param uuid 订单UUID
     */
    private void checkAndBanIfNeeded(HouseOrder order, String uuid) {
        // 只对未支付且逾期的订单进行封禁检查
        if (order.getStatus() != null && order.getStatus() == 1) {
            return; // 已支付，不需要封禁
        }

        if (order.getDeadline() == null || uuid == null || uuid.trim().isEmpty()) {
            return; // 缺少必要信息，跳过
        }

        // 计算逾期天数
        Timestamp currentTime = Timestamp.valueOf(LocalDateTime.now());
        long diffInMillis = currentTime.getTime() - order.getDeadline().getTime();

        if (diffInMillis <= 0) {
            return; // 未逾期，不需要封禁
        }

        long diffInDays = (diffInMillis + 24 * 60 * 60 * 1000 - 1) / (24 * 60 * 60 * 1000);

        if (diffInDays <= 180) {
            return; // 未超过180天，不需要封禁
        }

        try {
            // 检查是否已经被封禁
            QueryWrapper<Ban> banQuery = new QueryWrapper<>();
            banQuery.eq("uuid", uuid);
            long existingBanCount = banMapper.selectCount(banQuery);

            if (existingBanCount > 0) {
                System.out.println("用户 " + order.getUserId() + " 已经因房屋订单 " + order.getId() + " 被封禁，跳过");
                return;
            }

            // 创建封禁记录
            Ban ban = new Ban();
            ban.setUuid(uuid);
            ban.setUserId(order.getUserId().longValue());
            ban.setBan(1); // 1表示封禁

            int inserted = banMapper.insert(ban);
            if (inserted > 0) {
                System.out.println("用户 " + order.getUserId() + " 因房屋订单 " + order.getId() +
                        " 逾期超过180天（" + diffInDays + "天）被封禁，UUID: " + uuid);
            } else {
                System.err.println("封禁用户 " + order.getUserId() + " 房屋订单 " + order.getId() + " 失败");
            }

        } catch (Exception e) {
            System.err.println("处理房屋订单 " + order.getId() + " 封禁检查时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 把 Timestamp 转换为 Instant（按北京时区）
     */
    private Instant parseToInstant(Timestamp timestamp) {
        return timestamp.toLocalDateTime().atZone(ZoneId.of("Asia/Shanghai")).toInstant();
    }
}